home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wlist.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-02  |  17.3 KB  |  799 lines

  1.  
  2.  
  3.  
  4.  
  5. #include "WINGsP.h"
  6.  
  7. char *WMListDidScrollNotification = "WMListDidScrollNotification";
  8. char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
  9.  
  10. typedef struct W_List {
  11.     W_Class widgetClass;
  12.     W_View *view;
  13.  
  14.     WMBag *items;         /* list of WMListItem */
  15.     
  16.     short selectedItem;
  17.     
  18.     short itemHeight;
  19.     
  20.     short topItem;               /* index of first visible item */
  21.     
  22.     short fullFitLines;               /* no of lines that fit entirely */
  23.  
  24.     void *clientData;
  25.     WMAction *action;
  26.     void *doubleClientData;
  27.     WMAction *doubleAction;
  28.     
  29.     WMListDrawProc *draw;
  30.     
  31.     WMHandlerID    *idleID;           /* for updating the scroller after
  32.                     * adding elements */
  33.  
  34.     WMScroller *vScroller;
  35.     /*
  36.     WMScroller *hScroller;
  37.      */
  38.  
  39.     struct {
  40.     unsigned int allowMultipleSelection:1;
  41.     unsigned int userDrawn:1;
  42.     unsigned int userItemHeight:1;
  43.     /* */
  44.     unsigned int dontFitAll:1;     /* 1 = last item won't be fully visible */
  45.     unsigned int redrawPending:1;
  46.     unsigned int buttonPressed:1;
  47.     unsigned int buttonWasPressed:1;
  48.     } flags;
  49. } List;
  50.  
  51.  
  52.  
  53. #define DEFAULT_WIDTH    150
  54. #define DEFAULT_HEIGHT    150
  55.  
  56.  
  57. static void destroyList(List *lPtr);
  58. static void paintList(List *lPtr);
  59.  
  60.  
  61. static void handleEvents(XEvent *event, void *data);
  62. static void handleActionEvents(XEvent *event, void *data);
  63. static void updateScroller(List *lPtr);
  64.  
  65. static void vScrollCallBack(WMWidget *scroller, void *self);
  66.  
  67. static void updateGeometry(WMList *lPtr);
  68. static void didResizeList();
  69.  
  70.  
  71. W_ViewDelegate _ListViewDelegate = {
  72.     NULL,
  73.     NULL,
  74.     didResizeList,
  75.     NULL,
  76.     NULL
  77. };
  78.  
  79.  
  80.           
  81. WMList*
  82. WMCreateList(WMWidget *parent)
  83. {
  84.     List *lPtr;
  85.     W_Screen *scrPtr = W_VIEW(parent)->screen;
  86.  
  87.     lPtr = wmalloc(sizeof(List));
  88.     memset(lPtr, 0, sizeof(List));
  89.  
  90.     lPtr->widgetClass = WC_List;
  91.  
  92.     lPtr->view = W_CreateView(W_VIEW(parent));
  93.     if (!lPtr->view) {
  94.     wfree(lPtr);
  95.     return NULL;
  96.     }
  97.     lPtr->view->self = lPtr;
  98.  
  99.     lPtr->view->delegate = &_ListViewDelegate;
  100.  
  101.     WMCreateEventHandler(lPtr->view, ExposureMask|StructureNotifyMask
  102.              |ClientMessageMask, handleEvents, lPtr);
  103.  
  104.     WMCreateEventHandler(lPtr->view, ButtonPressMask|ButtonReleaseMask
  105.              |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
  106.              handleActionEvents, lPtr);
  107.  
  108.     lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
  109.  
  110.     lPtr->items = WMCreateBag(4);
  111.  
  112.     /* create the vertical scroller */
  113.     lPtr->vScroller = WMCreateScroller(lPtr);
  114.     WMMoveWidget(lPtr->vScroller, 1, 1);
  115.     WMSetScrollerArrowsPosition(lPtr->vScroller, WSAMaxEnd);
  116.  
  117.     WMSetScrollerAction(lPtr->vScroller, vScrollCallBack, lPtr);
  118.  
  119.     /* make the scroller map itself when it's realized */
  120.     WMMapWidget(lPtr->vScroller);
  121.  
  122.     W_ResizeView(lPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  123.     
  124.     lPtr->selectedItem = -1;
  125.  
  126.     return lPtr;
  127. }
  128.  
  129.  
  130. static int
  131. comparator(const void *a, const void *b)
  132. {
  133.     return (strcmp((*(WMListItem**)a)->text, (*(WMListItem**)b)->text));
  134. }
  135.  
  136.  
  137. void
  138. WMSortListItems(WMList *lPtr)
  139. {
  140.     WMSortBag(lPtr->items, comparator);
  141.  
  142.     paintList(lPtr);
  143. }
  144.  
  145.  
  146.  
  147. void
  148. WMSortListItemsWithComparer(WMList *lPtr, int (f)(const void*, const void*))
  149. {
  150.     WMSortBag(lPtr->items, f);
  151.  
  152.     paintList(lPtr);
  153. }
  154.  
  155.  
  156.  
  157. WMListItem*
  158. WMInsertListItem(WMList *lPtr, int row, char *text)
  159. {
  160.     WMListItem *item;
  161.  
  162.     CHECK_CLASS(lPtr, WC_List);
  163.  
  164.     item = wmalloc(sizeof(WMListItem));
  165.     memset(item, 0, sizeof(WMListItem));
  166.     item->text = wstrdup(text);
  167.  
  168.  
  169.     if (lPtr->selectedItem >= row && lPtr->selectedItem >= 0
  170.     && row >= 0)
  171.     lPtr->selectedItem++;
  172.     
  173.     row = WMIN(row, WMGetBagItemCount(lPtr->items));
  174.     
  175.     if (row < 0)
  176.     WMPutInBag(lPtr->items, item);
  177.     else
  178.     WMInsertInBag(lPtr->items, row, item);
  179.  
  180.     /* update the scroller when idle, so that we don't waste time
  181.      * updating it when another item is going to be added later */
  182.     if (!lPtr->idleID) {
  183.     lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
  184.     } 
  185.  
  186.     return item;
  187. }
  188.  
  189.  
  190. void
  191. WMRemoveListItem(WMList *lPtr, int row)
  192. {
  193.     WMListItem *item;
  194.     int topItem = lPtr->topItem;
  195.     int selNotify = 0;
  196.  
  197.     CHECK_CLASS(lPtr, WC_List);
  198.     
  199.     if (row < 0 || row >= WMGetBagItemCount(lPtr->items))
  200.     return;
  201.  
  202.     if (lPtr->selectedItem == row) {
  203.         lPtr->selectedItem = -1;
  204.         selNotify = 1;
  205.     } else if (lPtr->selectedItem > row) {
  206.         lPtr->selectedItem--;
  207.     }
  208.  
  209.     if (row <= lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll)
  210.     lPtr->topItem--;
  211.     if (lPtr->topItem < 0)
  212.     lPtr->topItem = 0;
  213.  
  214.     item = WMGetFromBag(lPtr->items, row);
  215.     if (item->text)
  216.     wfree(item->text);
  217.     wfree(item);
  218.  
  219.     WMDeleteFromBag(lPtr->items, row);
  220.  
  221.     if (!lPtr->idleID) {
  222.     lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
  223.     }
  224.     if (lPtr->topItem != topItem)
  225.         WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
  226.     if (selNotify)
  227.         WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr,
  228.                                (void*)((int)lPtr->selectedItem));
  229. }
  230.  
  231.  
  232.  
  233. WMListItem*
  234. WMGetListItem(WMList *lPtr, int row)
  235. {
  236.     return WMGetFromBag(lPtr->items, row);
  237. }
  238.  
  239.  
  240. WMBag*
  241. WMGetListItems(WMList *lPtr)
  242. {
  243.     return lPtr->items;
  244. }
  245.  
  246.  
  247.  
  248. void
  249. WMSetListUserDrawProc(WMList *lPtr, WMListDrawProc *proc)
  250. {
  251.     lPtr->flags.userDrawn = 1;
  252.     lPtr->draw = proc;
  253. }
  254.  
  255.  
  256. void
  257. WMSetListUserDrawItemHeight(WMList *lPtr, unsigned short height)
  258. {
  259.     assert(height > 0);
  260.     
  261.     lPtr->flags.userItemHeight = 1;
  262.     lPtr->itemHeight = height;
  263.     
  264.     updateGeometry(lPtr);
  265. }
  266.  
  267.  
  268. void
  269. WMClearList(WMList *lPtr)
  270. {
  271.     WMListItem *item;
  272.     int oldSelected = lPtr->selectedItem;
  273.     int i;
  274.  
  275.     for (i = 0; i < WMGetBagItemCount(lPtr->items); i++) {
  276.     item = WMGetFromBag(lPtr->items, i);
  277.     wfree(item->text);
  278.     wfree(item);
  279.     }
  280.     WMEmptyBag(lPtr->items);
  281.  
  282.     lPtr->topItem = 0;
  283.     lPtr->selectedItem = -1;
  284.  
  285.     if (!lPtr->idleID) {
  286.     WMDeleteIdleHandler(lPtr->idleID);
  287.     lPtr->idleID = NULL;
  288.     }
  289.     if (lPtr->view->flags.realized) {
  290.     updateScroller(lPtr);
  291.     }
  292.     if (oldSelected != -1)
  293.         WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr,
  294.                                (void*)-1);
  295. }
  296.  
  297.  
  298. void
  299. WMSetListAction(WMList *lPtr, WMAction *action, void *clientData)
  300. {
  301.     lPtr->action = action;
  302.     lPtr->clientData = clientData;
  303. }
  304.  
  305.  
  306. void
  307. WMSetListDoubleAction(WMList *lPtr, WMAction *action, void *clientData)
  308. {
  309.     lPtr->doubleAction = action;
  310.     lPtr->doubleClientData = clientData;
  311. }
  312.  
  313.  
  314. WMListItem*
  315. WMGetListSelectedItem(WMList *lPtr)
  316. {
  317.     if (lPtr->selectedItem < 0)
  318.     return NULL;
  319.  
  320.     return WMGetFromBag(lPtr->items, lPtr->selectedItem);
  321. }
  322.  
  323.  
  324. int
  325. WMGetListSelectedItemRow(WMList *lPtr)
  326. {    
  327.     return lPtr->selectedItem;
  328. }
  329.  
  330.  
  331. int
  332. WMGetListItemHeight(WMList *lPtr)
  333. {    
  334.     return lPtr->itemHeight;
  335. }
  336.  
  337.  
  338. void
  339. WMSetListPosition(WMList *lPtr, int row)
  340. {
  341.     lPtr->topItem = row;
  342.     if (lPtr->topItem + lPtr->fullFitLines > WMGetBagItemCount(lPtr->items))
  343.     lPtr->topItem = WMGetBagItemCount(lPtr->items) - lPtr->fullFitLines;
  344.  
  345.     if (lPtr->topItem < 0)
  346.     lPtr->topItem = 0;
  347.     
  348.     if (lPtr->view->flags.realized)
  349.     updateScroller(lPtr);
  350. }
  351.  
  352.  
  353. void
  354. WMSetListBottomPosition(WMList *lPtr, int row)
  355. {
  356.     if (WMGetBagItemCount(lPtr->items) > lPtr->fullFitLines) {
  357.     lPtr->topItem = row - lPtr->fullFitLines;
  358.     if (lPtr->topItem < 0)
  359.         lPtr->topItem = 0;
  360.     if (lPtr->view->flags.realized)
  361.         updateScroller(lPtr);
  362.     }
  363. }
  364.  
  365.  
  366. int
  367. WMGetListNumberOfRows(WMList *lPtr)
  368. {
  369.     return WMGetBagItemCount(lPtr->items);
  370. }
  371.  
  372. int
  373. WMGetListPosition(WMList *lPtr)
  374. {
  375.     return lPtr->topItem;
  376. }
  377.  
  378.  
  379. static void
  380. vScrollCallBack(WMWidget *scroller, void *self)
  381. {
  382.     WMList *lPtr = (WMList*)self;
  383.     WMScroller *sPtr = (WMScroller*)scroller;
  384.     int height;
  385.     int topItem = lPtr->topItem;
  386.     int itemCount = WMGetBagItemCount(lPtr->items);
  387.     
  388.     height = lPtr->view->size.height - 4;
  389.  
  390.     switch (WMGetScrollerHitPart(sPtr)) {
  391.      case WSDecrementLine:
  392.     if (lPtr->topItem > 0) {
  393.         lPtr->topItem--;
  394.  
  395.         updateScroller(lPtr);
  396.     }
  397.     break;
  398.     
  399.      case WSDecrementPage:
  400.     if (lPtr->topItem > 0) {
  401.         lPtr->topItem -= lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
  402.         if (lPtr->topItem < 0)
  403.         lPtr->topItem = 0;
  404.  
  405.         updateScroller(lPtr);
  406.     }
  407.     break;
  408.  
  409.     
  410.      case WSIncrementLine:
  411.     if (lPtr->topItem + lPtr->fullFitLines < itemCount) {
  412.         lPtr->topItem++;
  413.         
  414.         updateScroller(lPtr);
  415.     }
  416.     break;
  417.     
  418.      case WSIncrementPage:
  419.     if (lPtr->topItem + lPtr->fullFitLines < itemCount) {
  420.         lPtr->topItem += lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
  421.  
  422.         if (lPtr->topItem + lPtr->fullFitLines > itemCount)
  423.         lPtr->topItem = itemCount - lPtr->fullFitLines;
  424.  
  425.         updateScroller(lPtr);
  426.     }
  427.     break;
  428.     
  429.      case WSKnob:
  430.     {
  431.         int oldTopItem = lPtr->topItem;
  432.         
  433.         lPtr->topItem = WMGetScrollerValue(lPtr->vScroller) * 
  434.         (float)(itemCount - lPtr->fullFitLines);
  435.  
  436.         if (oldTopItem != lPtr->topItem)
  437.         paintList(lPtr);
  438.     }
  439.     break;
  440.  
  441.      case WSKnobSlot:
  442.      case WSNoPart:
  443.     /* do nothing */
  444.     break;
  445.     }
  446.  
  447.     if (lPtr->topItem != topItem)
  448.     WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
  449. }
  450.  
  451.  
  452. static void
  453. paintItem(List *lPtr, int index)
  454. {
  455.     WMView *view = lPtr->view;
  456.     W_Screen *scr = view->screen;
  457.     int width, height, x, y;
  458.     WMListItem *itemPtr;
  459.  
  460.     itemPtr = WMGetFromBag(lPtr->items, index);
  461.  
  462.     width = lPtr->view->size.width - 2 - 19;
  463.     height = lPtr->itemHeight;
  464.     x = 19;
  465.     y = 2 + (index-lPtr->topItem) * lPtr->itemHeight + 1;
  466.  
  467.     if (lPtr->flags.userDrawn) {
  468.     WMRect rect;
  469.     int flags;
  470.  
  471.     rect.size.width = width;
  472.     rect.size.height = height;
  473.     rect.pos.x = x;
  474.     rect.pos.y = y;
  475.  
  476.     flags = itemPtr->uflags;
  477.     if (itemPtr->disabled)
  478.         flags |= WLDSDisabled;
  479.     if (itemPtr->selected)
  480.         flags |= WLDSSelected;
  481.     if (itemPtr->isBranch)
  482.         flags |= WLDSIsBranch;
  483.  
  484.     if (lPtr->draw)
  485.         (*lPtr->draw)(lPtr, index, view->window, itemPtr->text, flags, 
  486.               &rect);
  487.     } else {
  488.     if (itemPtr->selected)
  489.         XFillRectangle(scr->display, view->window, WMColorGC(scr->white), 
  490.                x, y, width, height);
  491.     else
  492.         XClearArea(scr->display, view->window, x, y, width, height, False);
  493.  
  494.     W_PaintText(view, view->window, scr->normalFont,  x+4, y, width,
  495.             WALeft, WMColorGC(scr->black), False, 
  496.             itemPtr->text, strlen(itemPtr->text));
  497.     }
  498. }
  499.  
  500.  
  501.  
  502. static void
  503. paintList(List *lPtr)
  504. {
  505.     W_Screen *scrPtr = lPtr->view->screen;
  506.     int i, lim;
  507.  
  508.     if (!lPtr->view->flags.mapped)
  509.     return;
  510.  
  511.     if (WMGetBagItemCount(lPtr->items) > 0) {
  512.     if (lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll 
  513.         > WMGetBagItemCount(lPtr->items)) {
  514.  
  515.         lim = WMGetBagItemCount(lPtr->items) - lPtr->topItem;
  516.         XClearArea(scrPtr->display, lPtr->view->window, 19,
  517.                2+lim*lPtr->itemHeight, lPtr->view->size.width-21,
  518.                lPtr->view->size.height-lim*lPtr->itemHeight-3, False);
  519.     } else {
  520.         lim = lPtr->fullFitLines + lPtr->flags.dontFitAll;
  521.     }
  522.     for (i = lPtr->topItem; i < lPtr->topItem + lim; i++) {
  523.         paintItem(lPtr, i);
  524.     }
  525.     } else {
  526.     XClearWindow(scrPtr->display, lPtr->view->window);
  527.     }
  528.     W_DrawRelief(scrPtr, lPtr->view->window, 0, 0, lPtr->view->size.width,
  529.          lPtr->view->size.height, WRSunken);
  530. }
  531.  
  532. #if 0
  533. static void
  534. scrollTo(List *lPtr, int newTop)
  535. {
  536.     
  537. }
  538. #endif
  539.  
  540. static void
  541. updateScroller(List *lPtr)
  542. {
  543.     float knobProportion, floatValue, tmp;
  544.     int count = WMGetBagItemCount(lPtr->items);
  545.  
  546.     if (lPtr->idleID)
  547.      WMDeleteIdleHandler(lPtr->idleID);
  548.     lPtr->idleID = NULL;
  549.         
  550.     paintList(lPtr);
  551.     
  552.     if (count == 0 || count <= lPtr->fullFitLines)
  553.     WMSetScrollerParameters(lPtr->vScroller, 0, 1);
  554.     else {
  555.     tmp = lPtr->fullFitLines;
  556.     knobProportion = tmp/(float)count;
  557.  
  558.     floatValue = (float)lPtr->topItem/(float)(count - lPtr->fullFitLines);
  559.  
  560.     WMSetScrollerParameters(lPtr->vScroller, floatValue, knobProportion);
  561.     }
  562. }
  563.  
  564.  
  565. static void
  566. handleEvents(XEvent *event, void *data)
  567. {
  568.     List *lPtr = (List*)data;
  569.  
  570.     CHECK_CLASS(data, WC_List);
  571.  
  572.  
  573.     switch (event->type) {    
  574.      case Expose:
  575.     if (event->xexpose.count!=0)
  576.         break;
  577.     paintList(lPtr);
  578.     break;
  579.     
  580.      case DestroyNotify:
  581.     destroyList(lPtr);
  582.     break;
  583.     
  584.     }
  585. }
  586.  
  587.  
  588. int
  589. WMFindRowOfListItemWithTitle(WMList *lPtr, char *title)
  590. {
  591.     WMListItem *item;
  592.     WMBagIterator i;
  593.     int ok = 0;
  594.     
  595.     WM_ITERATE_BAG(lPtr->items, item, i) {
  596.     if (strcmp(item->text, title)==0) {
  597.         ok = 1;
  598.         break;
  599.     }
  600.     }
  601.  
  602.     return ok ? WMBagIndexForIterator(lPtr->items, i) : -1;
  603. }
  604.  
  605.  
  606. void
  607. WMSelectListItem(WMList *lPtr, int row)
  608. {
  609.     WMListItem *itemPtr;
  610.     int notify = 0;
  611.  
  612.     if (row >= WMGetBagItemCount(lPtr->items))
  613.     return;
  614.  
  615.     /* the check below must be changed when the multiple selection is
  616.      * implemented. -Dan
  617.      */
  618.     if (!lPtr->flags.allowMultipleSelection && row == lPtr->selectedItem)
  619.         notify = 0;
  620.     else
  621.         notify = 1;
  622.  
  623.     assert(lPtr->selectedItem < WMGetBagItemCount(lPtr->items));
  624.     
  625.     if (!lPtr->flags.allowMultipleSelection) {
  626.     /* unselect previous selected item */
  627.     if (lPtr->selectedItem >= 0) {
  628.         itemPtr = WMGetFromBag(lPtr->items, lPtr->selectedItem);
  629.  
  630.         if (itemPtr->selected) {
  631.         itemPtr->selected = 0;
  632.         if (lPtr->view->flags.mapped 
  633.             && lPtr->selectedItem>=lPtr->topItem
  634.             && lPtr->selectedItem<=lPtr->topItem+lPtr->fullFitLines) {
  635.             paintItem(lPtr, lPtr->selectedItem);
  636.         }
  637.         }
  638.     }
  639.     }
  640.     
  641.     if (row < 0) {
  642.         if (!lPtr->flags.allowMultipleSelection) {
  643.         lPtr->selectedItem = -1;
  644.             if (notify)
  645.                 WMPostNotificationName(WMListSelectionDidChangeNotification,
  646.                                        lPtr, (void*)((int)lPtr->selectedItem));
  647.         }
  648.     return;
  649.     }
  650.  
  651.     /* select item */
  652.     itemPtr = WMGetFromBag(lPtr->items, row);
  653.  
  654.     if (lPtr->flags.allowMultipleSelection)
  655.     itemPtr->selected = !itemPtr->selected;
  656.     else
  657.     itemPtr->selected = 1;
  658.  
  659.     if (lPtr->view->flags.mapped) {
  660.     paintItem(lPtr, row);
  661.  
  662.     if ((row-lPtr->topItem+lPtr->fullFitLines)*lPtr->itemHeight
  663.         > lPtr->view->size.height-2)
  664.         W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0,
  665.              lPtr->view->size.width, lPtr->view->size.height,
  666.              WRSunken);
  667.     }
  668.     lPtr->selectedItem = row;
  669.     if (notify)
  670.         WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr,
  671.                                (void*)((int)lPtr->selectedItem));
  672. }
  673.  
  674.  
  675. static int
  676. getItemIndexAt(List *lPtr, int clickY)
  677. {
  678.     int index;
  679.  
  680.     index = (clickY - 2) / lPtr->itemHeight + lPtr->topItem;
  681.  
  682.     if (index < 0 || index >= WMGetBagItemCount(lPtr->items))
  683.     return -1;
  684.  
  685.     return index;
  686. }
  687.  
  688.  
  689. static void
  690. handleActionEvents(XEvent *event, void *data)
  691. {
  692.     List *lPtr = (List*)data;
  693.     int tmp;
  694.     int topItem = lPtr->topItem;
  695.  
  696.     CHECK_CLASS(data, WC_List);
  697.  
  698.     switch (event->type) {
  699.      case ButtonRelease:
  700.     lPtr->flags.buttonPressed = 0;
  701.     tmp = getItemIndexAt(lPtr, event->xbutton.y);
  702.  
  703.     if (tmp == lPtr->selectedItem && tmp >= 0) {
  704.         if (lPtr->action)
  705.         (*lPtr->action)(lPtr, lPtr->clientData);
  706.     }
  707.     break;
  708.  
  709.      case EnterNotify:
  710.     lPtr->flags.buttonPressed = lPtr->flags.buttonWasPressed;
  711.     lPtr->flags.buttonWasPressed = 0;
  712.     break;
  713.  
  714.      case LeaveNotify:
  715.     lPtr->flags.buttonWasPressed = lPtr->flags.buttonPressed;
  716.     lPtr->flags.buttonPressed = 0;
  717.     break;
  718.  
  719.      case ButtonPress:
  720.     if (event->xbutton.x > WMWidgetWidth(lPtr->vScroller)) {
  721.         tmp = getItemIndexAt(lPtr, event->xbutton.y);
  722.         lPtr->flags.buttonPressed = 1;
  723.  
  724.         if (tmp >= 0) {
  725.         if (tmp == lPtr->selectedItem && WMIsDoubleClick(event)) {
  726.             WMSelectListItem(lPtr, tmp);
  727.             if (lPtr->doubleAction)
  728.             (*lPtr->doubleAction)(lPtr, lPtr->doubleClientData);
  729.         } else {
  730.             WMSelectListItem(lPtr, tmp);
  731.         }
  732.         }
  733.     }
  734.     break;
  735.     
  736.      case MotionNotify:
  737.     if (lPtr->flags.buttonPressed) {
  738.         tmp = getItemIndexAt(lPtr, event->xmotion.y);
  739.         if (tmp>=0 && tmp != lPtr->selectedItem) {
  740.         WMSelectListItem(lPtr, tmp);
  741.         }
  742.     }
  743.     break;
  744.     }
  745.     if (lPtr->topItem != topItem)
  746.         WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
  747. }
  748.  
  749.  
  750. static void
  751. updateGeometry(WMList *lPtr)
  752. {    
  753.     lPtr->fullFitLines = (lPtr->view->size.height - 4) / lPtr->itemHeight;
  754.     if (lPtr->fullFitLines * lPtr->itemHeight < lPtr->view->size.height - 4) {
  755.     lPtr->flags.dontFitAll = 1;
  756.     } else {
  757.     lPtr->flags.dontFitAll = 0;
  758.     }
  759.  
  760.     if (WMGetBagItemCount(lPtr->items) - lPtr->topItem <= lPtr->fullFitLines) {
  761.     lPtr->topItem = WMGetBagItemCount(lPtr->items) - lPtr->fullFitLines;
  762.     if (lPtr->topItem < 0)
  763.         lPtr->topItem = 0;
  764.     }
  765.  
  766.     updateScroller(lPtr);
  767. }
  768.  
  769.  
  770. static void
  771. didResizeList(W_ViewDelegate *self, WMView *view)
  772. {    
  773.     WMList *lPtr = (WMList*)view->self;
  774.  
  775.     WMResizeWidget(lPtr->vScroller, 1, view->size.height-2);
  776.  
  777.     updateGeometry(lPtr);
  778. }
  779.  
  780.  
  781. static void
  782. destroyList(List *lPtr)
  783. {
  784.     WMListItem *item;
  785.     WMBagIterator i;
  786.     
  787.     if (lPtr->idleID)
  788.      WMDeleteIdleHandler(lPtr->idleID);
  789.     lPtr->idleID = NULL;
  790.  
  791.     WM_ITERATE_BAG(lPtr->items, item, i) {
  792.     wfree(item->text);
  793.     wfree(item);
  794.     }
  795.     WMFreeBag(lPtr->items);
  796.     
  797.     wfree(lPtr);
  798. }
  799.